﻿namespace Trading.IBApi

open com.ib.client
open System

type LifeSpan =
    | Weekly
    | Monthly
    | Quarterly
    | LEAPS

type OptionChain(underlying: string, lifeSpan: LifeSpan, year: int, month: int, ?week: int) =

    let nthWeekdayInMonth (nth: int, weekday: DayOfWeek, year: int, month: int) =
        [| for day in 1..DateTime.DaysInMonth(year, month) -> DateTime(year, month, day) |]
        |> Array.filter (fun x -> x.DayOfWeek = weekday)
        |> function
            | x when nth >= 1 && nth <= x.Length -> Some(x.[nth - 1])
            | _ -> None

    let expiration =
        match lifeSpan with
        | Monthly -> nthWeekdayInMonth(3, DayOfWeek.Saturday, year, month)
        | Weekly -> nthWeekdayInMonth(week.Value, DayOfWeek.Friday, year, month)
        | Quarterly | LEAPS -> None

    member this.Underlying = underlying
    member this.Expiration = expiration

type ExerciseStyle = American | European
type SettlementStyle = Equity | Cash
type SettlementTime = AM | PM | Noon

type OptionRight = 
    | Call 
    | Put
    override this.ToString() = match this with | Call -> "C" | Put -> "P"

type OptionContract(underlying : string, lifeSpan : LifeSpan, expiry : DateTime, strike : double, right : OptionRight) =
    inherit Contract(
        m_symbol = underlying, 
        m_expiry = expiry.ToString("yyyyMMdd"), 
        m_strike = strike, 
        m_right = string right,
        m_exchange = "SMART", 
        m_secType = "OPT"
    )

    let listedOn = expiry.AddDays(-7.)

    static member Weekly(underlying, expiry, strike, right) = 
        OptionContract(underlying, LifeSpan.Weekly, expiry, strike, right)

    static member WeeklyCall(underlying, expiry, strike) = OptionContract(underlying, LifeSpan.Weekly, expiry, strike, Call)
    static member WeeklyPut(underlying, expiry, strike) = OptionContract(underlying, LifeSpan.Weekly, expiry, strike, Put)

    static member Monthly(underlying, expiry, strike, right) = 
        OptionContract(underlying, LifeSpan.Monthly, expiry, strike, right)

    static member Leaps(underlying, expiry, strike, right) = 
        OptionContract(underlying, LifeSpan.LEAPS, expiry, strike, right)

    member this.ListedOn = listedOn

